// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2004-8-26

#ifndef __SOCKTOOL_H_COMMON_BASE__
#define __SOCKTOOL_H_COMMON_BASE__

#pragma once

#include "thread.h"
#include "singlelist.h"

class CJoySockBase;
class CJoySockData;
class CJoySockRecvData;

//##ModelId=44C4B5F50243
enum SOCK_ASY_MESSAGE
{
	//##ModelId=44C4B5F50252
    SAM_BASE = WM_USER+0x39,
	//##ModelId=44C4B5F50253
    SAM_RECV_DATA,
	//##ModelId=44C4B5F50261
    SAM_CLOSE_SOCK,
	//##ModelId=44C4B5F50262
    SAM_CONNECTED,
	//##ModelId=44C4B5F50263
    SAM_ACCEPT,
};

//##ModelId=44C4B5F50271
class CJoySockConnect
{
public:
	//##ModelId=44C4B5F50273
    CJoySockData*   m_data;
	//##ModelId=44C4B5F50281
    sockaddr_in     m_addr;
};
/*
class CJoySockAccept
{
public:
    CJoySockData*   m_data;
    void*   m_callerData;
    int     m_callerDataSize;
    CJoySockAccept()
    {
        memset(this, 0, sizeof(CJoySockAccept));
    }
    ~CJoySockAccept()
    {
        if(m_callerData != NULL)
        {
            delete m_callerData;
        }
    }
};
*/
//##ModelId=44C4B5F502DE
class CJoySocketTool
{
public:
    // types.
	//##ModelId=44C4B5F600DA
    typedef CMap<SOCKET, SOCKET, CJoySockBase*, CJoySockBase*> CSockMap;
	//##ModelId=44C4B5F600DC
    class CThreadData
    {
    public:
		//##ModelId=44C4B5F600DD
        HANDLE  m_hThread;
		//##ModelId=44C4B5F600EA
        DWORD   m_dwThreadId;
		//##ModelId=44C4B5F600EB
        CThreadData()
            : m_hThread(NULL), m_dwThreadId(0)
        {
        }
    };
	//##ModelId=44C4B5F600FA
    struct CClearThread
    {
		//##ModelId=44C4B5F600FC
        HANDLE  m_hThread;
		//##ModelId=44C4B5F600FD
        HANDLE  m_hEvent;
		//##ModelId=44C4B5F600FE
        DWORD   m_dwWaitTime;
		//##ModelId=44C4B5F60109
        CList<HANDLE>   m_threads;
		//##ModelId=44C4B5F6010B
        CJoyCriticalSection m_lock;

		//##ModelId=44C4B5F60119
        int PeekThreads(HANDLE* pHandle, int c);
    };

    // datas.
	//##ModelId=44C4B5F502EE
    volatile    bool m_shutdown;
	//##ModelId=44C4B5F502EF
    DWORD       m_timeOut;
	//##ModelId=44C4B5F502F1
    CSockMap    m_socks;
	//##ModelId=44C4B5F50300
    CJoyCriticalSection m_lock;

	//##ModelId=44C4B5F50304
    HWND        m_hAsyWnd;

	//##ModelId=44C4B5F5030E
    CClearThread    m_clearThread;

	//##ModelId=44C4B5F50312
    CJoySocketTool();
	//##ModelId=44C4B5F5031C
    ~CJoySocketTool();

    // clear threads.
	//##ModelId=44C4B5F5032C
    DWORD ClearThreadProc(void*);
	//##ModelId=44C4B5F5033C
    static DWORD WINAPI sClearThreadProc(void* pContext);
	//##ModelId=44C4B5F5034B
    bool CreateClearThread();
	//##ModelId=44C4B5F5035B
    void CloseClearThread();
	//##ModelId=44C4B5F5036B
    void AddClearThread(HANDLE hThread);



	//##ModelId=44C4B5F5037A
    HANDLE CreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, void* pContext, bool bSuspend = false);


	//##ModelId=44C4B5F5038A
    bool CreateAsyWindow();
	//##ModelId=44C4B5F50399
    void DestroyAsyWindow();
	//##ModelId=44C4B5F503A9
    LRESULT AsyWindowProc(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam);
	//##ModelId=44C4B5F503C8
    static LRESULT CALLBACK sAsyWindowProc(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam);
	//##ModelId=44C4B5F60000
    void PostAsyMessage(UINT nMessage, WPARAM wParam, LPARAM lParam)
    {
        PostMessage(m_hAsyWnd, nMessage, wParam, lParam);
    }
	//##ModelId=44C4B5F60004
    void SendAsyMessage(UINT nMessage, WPARAM wParam, LPARAM lParam)
    {
        SendMessage(m_hAsyWnd, nMessage, wParam, lParam);
    }

    // do connect.
	//##ModelId=44C4B5F60012
    DWORD ConnectThreadProc(void*);
	//##ModelId=44C4B5F6001F
    static DWORD WINAPI sConnectThreadProc(void*);

    // do listen
	//##ModelId=44C4B5F6002E
    DWORD ListenThreadProc(void*);
	//##ModelId=44C4B5F60030
    static DWORD WINAPI sListenThreadProc(void*);

    // do send
	//##ModelId=44C4B5F60033
    DWORD SendThreadProc(void*);
	//##ModelId=44C4B5F6003F
    DWORD SendBlockThreadProc(void*);
	//##ModelId=44C4B5F6004E
    DWORD SendToThreadProc(void*);
	//##ModelId=44C4B5F60050
    static DWORD WINAPI sSendThreadProc(void*);
	//##ModelId=44C4B5F6005D
    static DWORD WINAPI sSendBlockThreadProc(void*);
	//##ModelId=44C4B5F6006D
    static DWORD WINAPI sSendToThreadProc(void*);

    // do recv
	//##ModelId=44C4B5F6007E
    CJoyCriticalSection m_recvLock;
	//##ModelId=44C4B5F6008E
    CJoySingleList<CJoySockRecvData>    m_recvDatas;

	//##ModelId=44C4B5F60092
	void JoySaveLog(const char* path, const char* logText);
	//##ModelId=44C4B5F6009C
	void DbPrint(const char* logText);
	//##ModelId=44C4B5F6009E
    void PostRecvData(CJoySockRecvData* pData);
	//##ModelId=44C4B5F600A0
    CJoySockRecvData* PeekRecvData();
	//##ModelId=44C4B5F600AB
    DWORD RecvThreadProc(void*);
	//##ModelId=44C4B5F600AD
    DWORD RecvBlockThreadProc(void*);
	//##ModelId=44C4B5F600BB
    DWORD RecvFromThreadProc(void*);
	//##ModelId=44C4B5F600BD
    static DWORD WINAPI sRecvThreadProc(void*);
	//##ModelId=44C4B5F600C0
    static DWORD WINAPI sRecvBlockThreadProc(void*);
	//##ModelId=44C4B5F600CD
    static DWORD WINAPI sRecvFromThreadProc(void*);

};

extern CJoySocketTool g_sockTool;


#endif  // __SOCKTOOL_H_COMMON_BASE__
